MAIN #include #include stdlib.h> #include - U

Anuncio
MAIN
#include <stdio.h>
#include <stdlib.h>
#include "tarea1.c"
//ejecucion y pruebas
int main(){
printf("\nSe adicionan los siguientes numeros al arbol\n");
arbol* Manzano = new_arbol(&ComparaPorBits);
int n = 10;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 20;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 4;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 7;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 0;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 15;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 30;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
n = 50;
printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n));
add_value(Manzano,n);
printf("------------------------\n");
printf("El arbol queda:\n");
print_arbol(Manzano);
printf("\nla funcion map con \"Sumar\" daría: %d\n\n",map(Manzano->values,&Sumar));
free_arbol(Manzano);
}
.H
typedef struct nodo {
int val;
struct nodo *left;
struct nodo *right;
} nodo;
typedef struct arbol {
nodo *values;
int (*func)(int,int);
} arbol;
arbol *new_arbol(int (*func)(int,int));
void add_value(arbol *a, int v);
nodo *print_arbol(arbol *a);
int map(nodo *n, int (*func)(int,int,int));
void free_arbol (arbol *a);
//Funciones Auxiliares
int ComparaPorBits(int a,int b);
int BitsEncendidos(int a);
int Sumar(int a,int b,int c);
void free_nodo (nodo *a);
void ImprimeNodo(nodo *a,int n);
.C
#include <stdio.h>
#include <stdlib.h>
#include "tarea1.h"
//implementacion de funciones propuestas
arbol *new_arbol(int (*func)(int,int)){
arbol* tree;
tree = (arbol *)malloc(sizeof(arbol));
if(tree==NULL) return tree;
tree -> values = NULL;
tree -> func = func;
return tree;
}
void add_value(arbol *a, int v){
if(a->values==NULL){
a -> values = (nodo *)malloc(sizeof(nodo));
a -> values -> val = v;
a -> values -> left = NULL;
a -> values -> right = NULL;
return ;
}
nodo* b = a->values;
nodo* c = b;
while(b!=NULL){
if(a->func(v,b->val)<1){
c = b;
b = b->left;
}else{
c = b;
b = b->right;
}
}
nodo* d = (nodo *)malloc(sizeof(nodo));
d -> val = v;
d -> left = NULL;
d -> right = NULL;
if(a->func(v,c->val)<1){
c->left = d;
}else{
c->right = d;
}
}
//Función auxiliar de impresion de nodos
void ImprimeNodo(nodo *a,int n){
int i;
for(i=0;i<n;i++){printf("\t");}
printf("-%d-\n",a->val);
if(a->left!=NULL){
ImprimeNodo(a->left,++n);
}else{
++n;
for(i=0;i<n;i++){printf("\t");}
printf("-*-\n");
}
if(a->right!=NULL){
ImprimeNodo(a->right,n);
}else{
for(i=0;i<n;i++){printf("\t");}
printf("-*-\n");
}
}
nodo *print_arbol(arbol *a){
printf("\n");
ImprimeNodo(a->values,0);
printf("\n");
return a->values;
}
//El arbol se imprime mostrando la raiz en el
//primer nivel, luego en el segundo nivel se
//muestra primero el hijo izquierdo y luego
//el derecho, asi recursivamente.
//Funcion borrado auxiliar
void free_nodo (nodo *a){
if(a->left!=NULL) free_nodo(a->left);
if(a->right!=NULL) free_nodo(a->right);
free(a);
}
void free_arbol (arbol *a){
if(a->values!=NULL) free_nodo(a->values);
free(a);
}
//Funciones auxiliares para map
int Sumar(int a,int b,int c){
return a+b+c;
}
int map(nodo *n, int (*func)(int,int,int)){
if(n->left==NULL && n->right==NULL) return n->val;
if(n->left==NULL && n->right!=NULL) return func(n->val,map(n->right,func),0);
if(n->left!=NULL && n->right==NULL) return func(n->val,map(n->left,func),0);
return func(n->val,map(n->right,func),map(n->left,func));
}
//función para obtener numero de bits encendidos
int BitsEncendidos(int a){
int total=0;
int i=0;
int b=a;
while(b!=0){
while(b%2==0){
b=b/2;
++i;
}
++total;
--b;
}
AUX 1
Pregunta 1: Implemente un programa equivalente al comando wc, que
permita contar el número de líneas, palabras y caracteres de un input.
Pregunta 2:
1. Escriba una función char * reverse(char *s) que recibe un
string de argumento y retorna el string invertido, usando punteros y no subíndices (no debe modificar el string original y debe
usar memoria dinámica para el resultado)
2. Escriba una función void reverse(char *s) que recibe un string
de argumento y lo modifica de forma de invertirlo en el mismo
lugar, sin pedir más memoria.
Pregunta 3: Escriba un programa que imprime los argumentos de una
función y el número correspondiente. Ejemplo:
./programa a b c
Nuestro ejecutable se
El argumento número 1
El argumento número 2
El argumento número 3
llama ./programa.
es a.
es b.
es c.
ANS
P1
#include <stdio.h>
#define IN 1 /* estamos dentro de una palabra */
#define OUT 0 /* estamos fuera de una palabra */
int main(){
int c, nl, np, nc, state;
state = OUT;
nl = np = nc = 0;
while((c = getchar()) != EOF){
++nc; /* agrego un caracter */
if(c== '\n') /* nueva linea */
++nl;
if(c == ' ' || c == '\n' || c == '\t') /* estoy fuera de una palabra */
state = OUT;
else if (state == OUT){ /* si estoy afuera y veo un caracter, entro a la palabra */
state = IN;
++np;
}
}
printf("%d %d %d\n", nl, np, nc);
}
P2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse1(char *s) {
char *p, *s2;
/* siempre lo primero, pedir memoria */
/* +1 por el 0 final */
p = (char *)malloc(strlen(s)+1);
/* s2 a la ultima posicion */
s2 = p+strlen(s);
/* pongo el 0 correspondiente y me muevo */
*s2-- = 0;
/* vamos iterando */
while(*s)
/* es lo mismo que != 0 -> termina cuando llego al 0 del final */
*s2-- = *s++;
return p;
}
void reverse2(char *s) {
char *p;
char aux;
/* pongo el puntero p en la ultima posicion menos el 0 */
p = s+strlen(s)-1;
while(p>s) { /* cuando se cruzan es que terminé de invertirlos */
aux = *s; /* guardamos primer caracter en el auxiliar */
*s++ = *p; /* copiamos en el primero el del final */
*p-- = aux; /* copiamos el auxiliar al final */
}
}
int main(){
char *str = "hola curso";
char *str2 = reverse1(str);
printf(" original: %s \n invertido: %s \n", str, str2);
reverse2(str2);
printf(" invertido de invertido: %s \n", str2);
free(str2); /* acordarse de liberar la memoria! */
return 0;
}
P3
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){ /*argc es el numero de argumentos, argv es un arreglo de strings (char
*) */
int i;
printf("Nuestro ejecutable se llama %s. \n", argv[0]); /* argv[0] siempre es el nombre de nuestro
ejecutable*/
for (i=1; i < argc ; i++){
printf("El argumento número %d es %s. \n", i, argv[i]);
}
return 0;
}
EXTRAS
PUNTEROS
#include <stdio.h>
int main(){
char *p = "hola";
/* & -> la direccion de lo apuntado */
printf("direccion de p? %p \n", &p);
/* qué significa que p sea un puntero? :O */
printf("lo que hay en p? %p \n", p);
/* *p es lo que hay en el lugar apuntado! si lo interpretamos como int será 'h' en ascii */
printf("lo que hay en el lugar apuntado por p? %d \n", *p);
/* o como un string, que nos dará todo el string hasta el 0 */
printf("lo que hay en el lugar apuntado por p? %s \n", (char *)p);
int i= 10;
/* podemos sacar la direccion de un int también */
printf("direccion de i? %p \n", &i);
/* pero dentro no hay un puntero, hay directamente un 10 */
printf("lo que hay en i? %d \n", i);
return 0;
}
STRING
#include <stdio.h>
#include <stdlib.h>
#include "string.h"
int main(){
char string[29] = "hola";
char *str1 = string;
printf("el string es %s \n", string);
printf("size string: %d, size *str: %d, length string: %d, length *str: %d \n", (int)sizeof(string),
(int)sizeof(str1),
(int)strlen(string), (int)strlen(str1));
int arreglo[] = {6, 5, 4, 3, 2, 1};
int *ptr;
int i;
ptr = &arreglo[0]; /* apuntamos al primer elemento del arreglo */
printf("\n\n");
for (i = 0; i < 6; i++)
{
printf("arreglo[%d] = %d ", i ,arreglo[i]); /*<-- A */
printf("ptr + %d = %d\n", i , *(ptr + i));
/*<-- B */
}
/* return 0 y probar hasta acá */
printf("\n\n");
char str[] = "Hola curso!";
char str2[20];
strcpy(str2, str1);
printf("El string copiado es %s \n", str2);
printf("\n\n");
/* comprarar y concatenar */
char str3[] = "hagamos";
char str4[] = "una prueba";
if(!strcmp(str3,str4))
/* == (strcmp(str3,str4) == 0)*/
printf("Strings iguales \n");
else
printf("Strings son distintos \n");
printf("\n\n");
char string5[22] = "hagamos ";
/* probar con 10 y ver que se cae */
char string6[] = "otra prueba!\n";
printf("%s\n", string5);
strcat(string5, string6);
printf("%s\n", string5);
printf("\n\n");
return 0;
}
AUX 2
Pregunta 1: Implemente un TDA diccionario usando lista enlazada y
árboles binarios, y compare ambas implementaciones usando entradas
ordenadas y desordenadas.
Pregunta 2 - C1 Primavera 2010:
Se le pide escribir un programa que verifique si la entrada estándar
tiene los paréntesis balanceados. Los paréntesis son “(,{,[” para abrir y
“),},]” para cerrar.
Para esto utilice siguiente implementación de pila:
typedef struct nodo {
char val;
struct nodo *next;
} stack;
stack *create_stack() {
stack *res = (stack *)malloc(sizeof(stack));
res->next = NULL;
}
int is_empty(stack *st) {
if (st == NULL || st->next == NULL)
return 1;
return 0;
}
1
void free_stack(stack *st) {
if (st == NULL) return;
free_stack(st->next);
free(st);
}
Usted debe implementar la función put y get, y el programa que utiliza
la pila para verificar el balanceo de paréntesis.
ANS
STACK
#include <stdio.h>
#include <stdlib.h>
typedef struct nodo {
char val;
struct nodo *next;
} stack;
stack *create_stack() {
stack *res = (stack *)malloc(sizeof(stack));
res->next = NULL;
return res;
}
void put(stack *st, char val) {
stack *res = (stack *)malloc(sizeof(stack));
res->val = val;
res->next = st->next;
st->next = res;
}
char get(stack *st) {
stack *aux = NULL;
if (st == NULL || st->next == NULL)
return EOF;
char res = st->next->val;
aux = st->next;
st->next = st->next->next;
free(aux);
return res;
}
int is_empty(stack *st) {
if (st == NULL || st->next == NULL)
return 1;
return 0;
}
void free_stack(stack *st) {
if (st->next == NULL) return;
free_stack(st->next);
free(st);
}
int main(int argc, char *argv[]) {
stack *st;
char c;
int non = 0;
st = create_stack();
while ((c = getchar()) != EOF && !non) {
/*print_stack(st);*/
switch (c) {
case '(':
put(st,c);
break;
case '{':
put(st,c);
break;
case '[':
put(st,c);
break;
case ')':
if (get(st) != '(')
non = 1;
break;
case '}':
if (get(st) != '{')
non = 1;
break;
case ']':
if (get(st) != '[')
non = 1;
break;
default: ;
}
}
if (!is_empty(st) || non)
printf("La entrada no tiene los parentesis balanceados\n");
else
printf("La entrada tiene los parentesis balanceados\n");
free_stack(st);
return 0;
}
DICT LISTA
#include <stdio.h>
#include <stdlib.h>
#include "dict-lista.h"
/*
* Tipo diccionario, implementado con listas enlazadas
*/
/*
* El primer elemento es una cabecera de lista que NO SE USA
*/
DICT *init_dict() {
DICT *p;
p = (DICT *)malloc(sizeof(DICT));
if(p == NULL) {
fprintf(stderr, "No mem!\n");
exit(1);
}
p->val = NULL;
p->next = NULL;
p->llave = NULL;
return p;
}
void add_dict(DICT *d, char *llave, void *val) {
DICT *p, *q;
for(p = d; p->next != NULL && strcmp(p->next->llave, llave) < 0 ; p=p->next)
;
if(p->next != NULL && strcmp(p->next->llave, llave) == 0)
p->next->val = val;
else {
q = (DICT *)malloc(sizeof(DICT));
q->val = val; q->llave = llave;
q->next = p->next;
p->next = q;
}
}
void *search_dict(DICT *d, char *llave) {
DICT *p;
for(p = d; p->next != NULL && strcmp(p->next->llave, llave) < 0 ; p=p->next)
;
if(p->next == NULL || strcmp(p->next->llave, llave) != 0)
return NULL;
return p->next->val;
}
void apply_dict(DICT *d, void (*f)(char *llave, void *val)) {
DICT *p;
for(p = d->next; p != NULL; p=p->next)
f(p->llave, p->val);
}
void stats_dict(DICT *d) {
int cnt = 0;
DICT *p;
for(p = d->next; p != NULL; p=p->next)
cnt++;
printf("DICT lista nodos = %d\n", cnt);
}
DICT ABB
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "dict-abb.h"
/*
* Tipo diccionario, implementado con Arboles Binarios de Busqueda
*/
/*
* Todas las funciones _abb son internas de la implementacion
* y son llamadas por la interfaz oficial de DICT
*/
DICT *init_dict() {
DICT *p;
p = (DICT *)malloc(sizeof(DICT));
if(p == NULL) {
fprintf(stderr, "No hay memoria!\n");
exit(1);
}
p->head = NULL;
return p;
}
/*
* Inserta un par en un ABB
* y retorna el nuevo ABB (con el par ya insertado)
*/
TREE *add_abb(TREE *t, char *llave, void *val) {
TREE *q;
int cmp;
if(t == NULL) { /* Insertar en un arbol vacio */
q = (TREE *) malloc(sizeof(TREE));
if(q == NULL) {
fprintf(stderr, "No hay memoria!\n");
exit(1);
}
q->llave = llave; q->val = val;
q->left = q->right = NULL;
return q;
}
cmp = strcmp(llave, t->llave);
if(cmp < 0)
t->left = add_abb(t->left, llave, val);
else if(cmp == 0)
t->val = val;
else
t->right = add_abb(t->right, llave, val);
return t;
}
void *search_abb(TREE *t, char *llave) {
int cmp;
if(t == NULL) return NULL;
cmp = strcmp(llave, t->llave);
if(cmp < 0)
return search_abb(t->left, llave);
else if(cmp == 0)
return t->val;
else
return search_abb(t->right, llave);
}
void apply_abb(TREE *t, void (*f)(char *llave, void *val)) {
if(t == NULL) return;
apply_abb(t->left, f);
f(t->llave, t->val);
apply_abb(t->right, f);
}
int nodos_abb(TREE *t) {
if(t == NULL) return 0;
return(nodos_abb(t->left)+nodos_abb(t->right)+1);
}
int max(int a, int b) {
return (a > b) ? a : b;
DICTLISTA.H
/*
* Tipo diccionario, implementado con listas enlazadas
*/
typedef struct dict_lista {
char *llave;
void *val;
struct dict_lista *next;
} DICT;
DICT *init_dict();
void add_dict(DICT *d, char *llave, void *val);
void *search_dict(DICT *d, char *llave);
void apply_dict(DICT *d, void (*f)(char *llave, void *val));
void stats_dict(DICT *d);\
AUX 3
Pregunta 1 - C1 Primavera 2007 Se quiere implementar un árbol binario con la representación entera hasta de 8 bits, para traducir
strings de bits. Los 0s van hacia la izquierda y los 1s a la derecha. Debe
utilizar la siguiente estructura:
typedef struct bin {
struct bin *izq, *der;
unsigned char val;
} ARBOL;
Se le pide escribir una función que, usando este árbol para 8 bits, traduzca un string de ceros y unos a un número entero. El string debe
tener un máximo de 8 bits para que la función lo transforme en un
char sin signo:
unsigned char bin2int(char *s, ARBOL *l);
Escriba también la función que construye el árbol para n bits:
ARBOL *construye_arbol(int val, int n);
Suponga que malloc siempre funciona y que los parámetros son correctos.
Ejemplo:
l = construye_arbol(0, 8);
printf("\%d\n", bits2char("11111111", l);
Debiera imprimir 255.
1
Pregunta 2
Para verificar errores de transmisión, se usa un bit de paridad que indica
si el número de bits en uno de una secuencia es par o impar. Se le pide
implementar dos funciones que permitan manejar bits de paridad en
un byte, suponiendo que los 7 bits de orden inferior son datos y el bit
8 de orden superior es un bit de paridad. La regla es: si el número de
bits en uno de los 7 inferiores es par, el octavo bit debe ir en 1. Si es
impar debe ir en 0.
unsigned charset_parity(unsigned char c);
int check_parity(unsigned char c);
Pregunta 3
Se desea aprovechar las capacidades de multicore de los actuales procesadores para escribir un programa que calcule el F ibonacci(n). Primero
escriba un programa sin threads (o con 1 thread) y luego multithread.
ANS
P1
#include <stdlib.h>
#include <stdio.h>
typedef struct bin{
struct bin *izq, *der;
unsigned char val;
} ARBOL;
ARBOL *construye_arbol(int val, int n){
ARBOL *p;
if (n < 0) return NULL;
p = (ARBOL *)malloc(sizeof(ARBOL));
p->val = val;
p->izq = construye_arbol(val<<1, n-1);
p->der = construye_arbol((val<<1)|1, n-1);
return p;
}
unsigned char bin2int(char *s, ARBOL *l){
if(l==NULL){
printf("llegue a null");
return 0;
}
if (*s == '\0'){
printf("ret: %d \n", l->val);
return l->val;
}
if (*s == '0'){
printf("0: %d \n", l->izq->val);
return bin2int(++s, l->izq);
}
if (*s == '1'){
printf("1: %d \n", l->der->val);
return bin2int(++s, l->der);
}
}
int main(){
ARBOL *l = construye_arbol(0, 8);
int x = bin2int("11111111", l);
free(l);
printf("%d\n",x);
return 0;
}
P2
#include <stdio.h>
unsigned char set_parity(unsigned char c){
int parity = 0x80;
int i;
/*1. mascara c c/r 1er bit: c&0x01 */
/*2. desplazarla: (c&0x01)<<i*/
/*3. ponerlo en el bit de paridad: <<(7-i)*/
for (i=0; i<7; i++)
parity ^= (c&0x01<<i)<<(7-i);
return parity|(c&0x7f); /*0111 1111*/
}
int check_parity(unsigned char c){
int parity = 0x80, check, i;
for(i=0; i<7; i++)
parity ^= (c&0x01<<i)<<(7-i);
check = c & 0x80; /* 1000 0000*/
printf("c = 0x%x, check = 0x%x, parity = 0x%x", c, check, parity);
return !(parity ^ check);
}
int main(){
char c = 0x77; /*0111 0111*/
printf("set_parity : &x \n", set_parity(c));
if(check_parity(set_parity(c))) printf ("paridad ok\n");
return 0;
}
P3
#include <stdio.h>
#include <pthread.h>
int fibonacci(int n){
if (n==0)
return 0;
else if (n==1)
return 1;
else
return fibonacci(n-1)+fibonacci(n-2);
}
void fib_thread(int *value){
int *p=value;
*p = fibonacci(*value);
}
void fib_multi(int *value){
int *p = value;
printf("thread trabajando con %d\n", *value);
if(*value == 0){
*p = 0;
return;
}
else if(*value ==1){
*p = 1;
return;
}
pthread_t pid1;
pthread_t pid2;
int prev1 = *value-1;
int prev2 = *value-2;
pthread_create(&pid1, NULL, (void *)fib_multi, &prev1);
pthread_create(&pid2, NULL, (void *)fib_multi, &prev2);
pthread_join(pid1, NULL);
pthread_join(pid2, NULL);
*p = prev1+prev2;
return;
}
int main(){
int value = 10;
pthread_t pid;
pthread_create(&pid, NULL, (void *)fib_thread, (void *)&value);
pthread_join(pid, NULL);
printf("resultado 1 thread: %d \n", value);
int value2 = 10;
pthread_t pid2;
pthread_create(&pid2, NULL, (void *)fib_multi, (void *)&value2);
pthread_join(pid2, NULL);
printf("resultado n thread: %d \n", value2);
return 0;
}
EXTRAS
THREADS
#include <stdio.h>
#include <pthread.h>
int main(){
pthread_t f1_thread, f2_thread;
void *f1(), *f2();
int i1 = 1;
int i2 = 2;
pthread_create(&f1_thread,NULL,f1,&i1);
pthread_create(&f2_thread,NULL,f2,&i2);
pthread_join(f1_thread,NULL);
pthread_join(f2_thread,NULL);
return 0;
}
void *f1(int *x){
int i=*x;
sleep(1);
printf("f1: %d\n",i);
pthread_exit(0);
}
void *f2(int *x){
int i=*x;
printf("f2: %d\n",i);
pthread_exit(0);
}
BITS
#include <stdlib.h>
#include <stdio.h>
int main(){
unsigned char a = 1; /*0000 0001*/
unsigned char b = 31; /*0001 1111*/
a ^=b;
printf("a^b = %d\n", a);
return 0;
}
AUX 4
Auxiliar N◦4 - Control 1
Profesor: José Miguel Piquer
Auxiliar: Javiera Born
18 de abril de 2012
Pregunta 1 - Control 1 Otoño 2011
Parte I
Implemente una función:
int binary("1010111101");
Que retorna el entero correspondiente a ese número binario. Suponga que
el string viene correcto y que el entero cabe en esta arquitectura.
Parte II
¿Qué hace esta función?:
int f() {
int l=1;
int i;
for(i=0; l != 0; i++)
l = l << 1;
return i; }
Parte III
Implemente una función:
int rev_endian(int n);
Que debe retornar el entero n representado en el endian inverso que esta
arquitectura: suponga que sólo existen big endian y little endian. Debe funcionar para cualquier tamanõ de los enteros, o sea, ser portable a cualquier
arquitectura.
1
Pregunta 2 - Control 1 Otoño 2011
Parte I
Se propone implementar un BOX con dos caracteres de capacidad en vez
de solo uno. Para ello usamos dos variables en la caja y dos punteros que
indican cual es la variable de donde leer y cual de donde escribir.
La sincronización se debe realizar usando dos mutexes por variable, uno
para escribir y otro para leer. Se les propone el siguiente código, donde sólo
falta agregar los mutexes para sincronizar.
typedef struct {
char c1, c2; char *in, *out;
pthread_mutex_t vacio1, lleno1, vacio2, lleno2;
} BOX;
BOX *createbox(){
BOX *b;
b = (BOX *)malloc(sizeof(BOX));
pthread_mutex_init(&b->vacio1, NULL);
pthread_mutex_init(&b->vacio2, NULL);
pthread_mutex_init(&b->lleno1, NULL);
pthread_mutex_init(&b->lleno2, NULL);
pthread_mutex_lock(&b->lleno1); /* Partimos con lleno tomado */
pthread_mutex_lock(&b->lleno2); /* Partimos con lleno tomado */
b-> in = b-> out = &b-> c1;
return(b);
}
void putbox(BOX *b, char c) {
if(b->in == &b->c1) {
b->c1 = c;
b->in = &b->c2;
}
if(b->in == &b->c2) {
b->c2 = c;
b->in = &b->c1;
}
}
2
char getbox(BOX *b){
char c;
if(b->out == &b->c1) {
c = b->c1;
b->out = &b->c2;
}
if(b->out == &b->c2) {
c = b->c2;
b->out = &b->c1;
}
return(c);
}
Modifique el código para que funcione para un productor y un consumidor.
Revise si funciona bien, y explique. Luego revise si funciona para N productores y N consumidores y proponga modificaciones si no funciona.
Parte II
Vimos en clases que una solución de sincronización con busy wait era
una pésima solución. Sin embargo, el profesor ejecutó un productor y un
consumidor y resultaba más eficiente que con mutexes. Explique por qué
sigue siendo cierto que busy wait es una pésima solución.
Pregunta 3 - Control 3 Otoño 2009
Se propone la siguiente solución a N buffers para múltiples productores y
consumidores:
void putbox(BOX *b, char c) {
pthread_mutex_lock(&b->mutex);
sem_wait(&b->vacios);
sem_post(&b->llenos);
b->buf[b->in] = c;
b->in = (b->in+1)%NBUFS;
pthread_mutex_unlock(&b->mutex);
}
3
char getbox(BOX *b){
char c;
pthread_mutex_lock(&b->mutex);
sem_wait(&b->llenos);
sem_post(&b->vacios);
c = b->buf[b->out];
b->out = (b->out+1)%NBUFS;
pthread_mutex_unlock(&b->mutex);
return(c);
}
Comente si está correcta, si permite paralelismo entre productores y consumidores y si no genera deadlocks. Explique su análisis y haga las menos
correcciones posibles que generen una solución correcta.
4
ANS
P1
#include <stdio.h>
/* PARTE 1 */
int binary(char *s) {
int res = 0; /*iniciamos el contador*/
while(*s != 0) { /* vamos leyendo el string*/
res <<= 1; /* shifteamos lo que ya llevamos */
if(*s == '1')
res = res+1; /*si es 1, cambiamos el 1 al final*/
s++;
}
return res;
}
/*
* ej: binary('1001')
*
1. res= 0, *s=1 -> res = 1;
*
2. res= 1 <<= res=10, *s=0 -> res = 10;
*
3. res=10 <<= res=100, *s=0 -> res = 100;
*
4. res=100 <<= res=1000, *s=1 -> res = 1001;
*
5. return res (como int).
*/
/* PARTE 2 */
int f() {
int l=1;
int i;
for(i=0; l != 0; i++)
l = l << 1;
return i;
}
/*Analicemos por partes qué es lo que hace:
* for:
* i=0: l=1.
* i=1: l=10.
* i=2: l=100
* ...
* i=n: l=000..00 (esto ocurrirá cuando el 1 haga overflow!)
* end
* => n nos dará el número de bits de 'int' en la arquitectura!
*/
/* PARTE 3 */
int rev_endian(int n) {
unsigned char *cp1, *cp2; /* trabajamos con unsigned para
* asegurar buen comportamiento */
int ret = 0; /*donde almacenaremos el resultado */
int i; /* contador */
cp1 = (unsigned char *) &n; /* puntero al n: será a su 1er bit */
cp2 = (unsigned char *) &ret + sizeof(ret) - 1; /* puntero al último bit de ret */
for(i=0; i < sizeof(ret); i++)
*cp2-- = *cp1++; /*copiamos cada bit del principio de n al final de ret y avanzamos */
return ret;
}
int main() { /* hacemos un pequeño main para probar nuestras funciones */
char *s = "1001";
int a = binary(s);
int b = f();
int c = rev_endian(1); /*Con esto podemos ver cual es el máximo: el resultado será 16777216, o en
binario, 1 0000 0000 0000 0000 0000 0000 :D */
printf("binary = %d, f = %d, rev_endian = %d", a, b, c);
return 0;
}
P2
/* PARTE 1 */
void putbox(BOX *b, char c) {
if(b->in == &b->c1) {
/* usaremos los mutex de la variable 1 */
/* primero bloqueamos vacio */
pthread_mutex_lock(&b->vacio1);
b->c1 = c;
/* y ahora desbloqueamos lleno */
pthread_mutex_unlock(&b->lleno1);
b->in = &b->c2;
}
/* Hacemos lo mismo para la otra variable */
if(b->in == &b->c2) {
pthread_mutex_lock(&b->vacio2);
b->c2 = c;
pthread_mutex_unlock(&b->lleno2);
b->in = &b->c1;
}
}
char getbox(BOX *b){
char c;
if(b->out == &b->c1) {
pthread_mutex_lock(&b->lleno1);
c = b->c1;
pthread_mutex_unlock(&b->vacio1);
b->out = &b->c2;
}
if(b->out == &b->c2) {
pthread_mutex_lock(&b->lleno2);
c = b->c2;
pthread_mutex_unlock(&b->vacio2);
b->out = &b->c1;
}
return(c);
}
/* Esta solucion funciona para 1 productor y 1 consumidor, porque no hay paralelismo al poner y sacar
datos:
* cuando uno escribe en c1, el otro lee en c2, y viceversa.
* Con N productores y N consumidores no va a funcionar por haber concurrencia sobre c1 y c2.
* Para arreglar esto, es necesario tener un mutex para put y otro para get, al entrar y salir de cada
funcion.
*/
/* PARTE 2*/
/* Busy Wait es una pésima solución por consumir una cantidad altísima de CPU al estar
constantemente preguntando por el bloqueo.
* Si cada bloqueo es corto, entonces puede resultar eficiente en tiempo de ejecución, pero igual gastará
mucho procesador.
*Si el bloqueo es largo, entonces es terrible en todo sentido, pues utilizará el 100% del procesador en
forma totalmente inútil.
*/
P3
/* Podemos ver una diferencia fundamental entre el wiki y el codigo propuesto:
* estamos usando el mismo mutex para put y get.
* Como este mutex es compartido, generamos un deadlock, ya que si nos bloqueamos en un wait
* el otro thread no podrá desbloquearnos, pues no podrá tomar el mutex.
* Entonces, debemos separar los mutex en 2 (put y get)
*/
void putbox(BOX *b, char c) {
pthread_mutex_lock(&b->mutex_put);
sem_wait(&b->vacios);
sem_post(&b->llenos);
b->buf[b->in] = c;
b->in = (b->in+1)%NBUFS;
pthread_mutex_unlock(&b->mutex_put);
}
char getbox(BOX *b){
char c;
pthread_mutex_lock(&b->mutex_get);
sem_wait(&b->llenos);
sem_post(&b->vacios);
c = b->buf[b->out];
b->out = (b->out+1)%NBUFS;
pthread_mutex_unlock(&b->mutex_get);
return(c);
}
/* Ahora tenemos otro error: hacemos un post de lleno antes de poner el dato
* luego puede despertar un get y sacar un dato aún no escrito (si in == out), y viceversa.
* Para arreglar esto debemos mover el post después del código que pone/saca el dato
* y como in/oyt no se comparte entre prod y cons, podemos postergarlo (la proteccion entre
* ellos ya está dada por el mutex)
*/
void putbox(BOX *b, char c) {
pthread_mutex_lock(&b->mutex_put);
sem_wait(&b->vacios);
b->buf[b->in] = c;
sem_post(&b->llenos);
b->in = (b->in+1)%NBUFS;
pthread_mutex_unlock(&b->mutex_put);
}
char getbox(BOX *b){
char c;
pthread_mutex_lock(&b->mutex_get);
sem_wait(&b->llenos);
c = b->buf[b->out];
sem_post(&b->vacios);
b->out = (b->out+1)%NBUFS;
pthread_mutex_unlock(&b->mutex_get);
return(c);
}
/* Ahora tendremos que efectivamente no hay deadlocks y hay buen paralelismo! */
Documentos relacionados
Descargar